AdderFusion
用 L1 距离(绝对差之和)替代标准卷积中的点积。输入、权重、输出均为 NHWC。 假定输入为 \(X\)、卷积核为 \(F\),按以下公式计算:
- 输入:
input_x - 输入数据地址
input_w - 卷积核权重地址
bias - 偏置地址
conv_param -
ConvParameter结构体地址,字段见下core_mask - 核掩码(仅共享存储版本)
ConvParameter 定义:
1typedef struct ConvParameter {
2 void* workspace_; // 仅 *_p 使用;*_s 不读(见 警告)
3 int output_batch_; // 输出 batch
4 int input_batch_; // 输入 batch
5 int input_h_; // 输入高
6 int input_w_; // 输入宽
7 int output_h_; // 输出高
8 int output_w_; // 输出宽
9 int input_channel_; // 输入通道
10 int output_channel_; // 输出通道
11 int kernel_h_; // 卷积核高
12 int kernel_w_; // 卷积核宽
13 int group_; // 组数
14 int pad_l_; // 左填充
15 int pad_u_; // 上填充
16 int dilation_h_; // 高方向膨胀
17 int dilation_w_; // 宽方向膨胀
18 int stride_h_; // 高方向步长
19 int stride_w_; // 宽方向步长
20 int buffer_size_; // 仅 *_p:元素个数;*_s 不读
21} ConvParameter;
- 输出:
out_y - 输出地址
- 支持平台:
FT78NEMT7004
警告
MT7004的workspace_ / buffer_size_ 分配算法(与前向 conv2d 相同;与 conv2d_transpose 不同:本算子 _s 不用 DDR workspace):
共享版 _s 不读 workspace_ / buffer_size_。LA 写死每核 AM 0x10000000,内部 BUFFER_SIZE = 65536 元素;布局 [im2col | packed weights] 各占一半。Host 无需在 DDR 上按 buffer_size_ 申请 workspace(可填 NULL / 0)。
C 参考与生产 LA 不一致:C golden 用 DDR workspace + logic_core_id × 2048;LA _s 用每核私有 AM。
私有版 _p 才读这两个字段。令 k = Kh × Kw × (Cin / G), chunk = buffer_size_ / k,须 buffer_size_ ≥ k(常用 max(2048, k))。 workspace 字节:
fp 私有 _p:buffer_size_ × sizeof(float)(仅 im2col)
hp 私有 _p:2 × buffer_size_ × sizeof(half)(im2col + 权重 pack)
推荐(_p):
k = Kh * Kw * (Cin / G); buffer_size_ = max(2048, k); /* 元素个数 */ /* fp: */ workspace_bytes = buffer_size_ * sizeof(float); /* hp: */ workspace_bytes = 2 * buffer_size_ * sizeof(half);
备注
FT78NE 支持 int8、fp32
MT7004 支持 fp16、fp32
共享存储版本:
-
void i8_adder_s(int8_t *input_x, int8_t *input_w, int8_t *out_y, int *bias, ConvParameter *conv_param, int core_mask)
-
void hp_adder_s(float16 *input_x, float16 *input_w, float16 *out_y, float16 *bias, ConvParameter *conv_param, int core_mask)
-
void fp_adder_s(float *input_x, float *input_w, float *out_y, float *bias, ConvParameter *conv_param, int core_mask)
C调用示例:
1// MT7004 示例(共享存储多核,DDR 地址)
2void TestAdderSMCFp32(int *input_shape, int *weight_shape, int *output_shape,
3 int *stride, int *padding, int *dilation, int groups,
4 float *bias, int core_mask) {
5 int core_id = get_core_id();
6 int logic_core_id = GetLogicCoreId(core_mask, core_id);
7 int core_num = GetCoreNum(core_mask);
8 float *input_data = (float *)0x88000000;
9 float *weight = (float *)0x89000000;
10 float *output_data = (float *)0x90000000;
11 float *bias_data = (float *)0x91000000;
12 ConvParameter *param = (ConvParameter *)0x92000000;
13 if (logic_core_id == 0) {
14 memcpy(bias_data, bias, sizeof(float) * output_shape[3]);
15 param->dilation_h_ = dilation[0];
16 param->dilation_w_ = dilation[1];
17 param->group_ = groups;
18 param->input_batch_ = input_shape[0];
19 param->input_h_ = input_shape[1];
20 param->input_w_ = input_shape[2];
21 param->input_channel_ = input_shape[3];
22 param->kernel_h_ = weight_shape[1];
23 param->kernel_w_ = weight_shape[2];
24 param->output_batch_ = output_shape[0];
25 param->output_h_ = output_shape[1];
26 param->output_w_ = output_shape[2];
27 param->output_channel_ = output_shape[3];
28 param->stride_h_ = stride[0];
29 param->stride_w_ = stride[1];
30 param->pad_u_ = padding[0];
31 param->pad_l_ = padding[2];
32 /* *_s 不读这两个字段;LA 使用每核 AM 0x10000000,BUFFER_SIZE=65536 */
33 param->workspace_ = NULL;
34 param->buffer_size_ = 0;
35 }
36 sys_bar(0, core_num);
37 fp_adder_s(input_data, weight, output_data, bias_data, param, core_mask);
38}
39
40void main() {
41 int in_channel = 4;
42 int out_channel = 4;
43 int groups = 2;
44 int input_shape[4] = {1, 18, 18, in_channel}; // NHWC
45 int weight_shape[4] = {out_channel, 3, 3, in_channel / groups};
46 int output_shape[4] = {1, 16, 16, out_channel}; // NHWC
47 int stride[2] = {1, 1};
48 int padding[4] = {0, 0, 0, 0};
49 int dilation[2] = {1, 1};
50 float bias[] = {1.0f, 2.0f, 3.0f, 4.0f};
51 int core_mask = 0b1111;
52 TestAdderSMCFp32(input_shape, weight_shape, output_shape,
53 stride, padding, dilation, groups, bias, core_mask);
54}
私有存储版本:
-
void i8_adder_p(int8_t *input_x, int8_t *input_w, int8_t *out_y, int *bias, ConvParameter *conv_param)
-
void hp_adder_p(float16 *input_x, float16 *input_w, float16 *out_y, float16 *bias, ConvParameter *conv_param)
-
void fp_adder_p(float *input_x, float *input_w, float *out_y, float *bias, ConvParameter *conv_param)
C调用示例:
1// MT7004 示例(私有存储单核,AM 地址)
2void TestAdderL2Fp32(int *input_shape, int *weight_shape, int *output_shape,
3 int *stride, int *padding, int *dilation, int groups,
4 float *bias) {
5 float *input_data = (float *)0x10010000;
6 float *weight = (float *)0x10020000;
7 float *output_data = (float *)0x10030000;
8 float *bias_data = (float *)0x10040000;
9 ConvParameter *param = (ConvParameter *)0x10060000;
10 memcpy(bias_data, bias, sizeof(float) * output_shape[3]);
11 param->dilation_h_ = dilation[0];
12 param->dilation_w_ = dilation[1];
13 param->group_ = groups;
14 param->input_batch_ = input_shape[0];
15 param->input_h_ = input_shape[1];
16 param->input_w_ = input_shape[2];
17 param->input_channel_ = input_shape[3];
18 param->kernel_h_ = weight_shape[1];
19 param->kernel_w_ = weight_shape[2];
20 param->output_batch_ = output_shape[0];
21 param->output_h_ = output_shape[1];
22 param->output_w_ = output_shape[2];
23 param->output_channel_ = output_shape[3];
24 param->stride_h_ = stride[0];
25 param->stride_w_ = stride[1];
26 param->pad_u_ = padding[0];
27 param->pad_l_ = padding[2];
28 /* *_p:buffer_size_ 元素个数,须 >= Kh*Kw*(Cin/G);FP workspace = 1*buffer_size_ */
29 param->workspace_ = (float *)0x10070000;
30 param->buffer_size_ = 2048;
31 fp_adder_p(input_data, weight, output_data, bias_data, param);
32}
33
34void main() {
35 int in_channel = 4;
36 int out_channel = 4;
37 int groups = 2;
38 int input_shape[4] = {1, 18, 18, in_channel}; // NHWC
39 int weight_shape[4] = {out_channel, 3, 3, in_channel / groups};
40 int output_shape[4] = {1, 16, 16, out_channel}; // NHWC
41 int stride[2] = {1, 1};
42 int padding[4] = {0, 0, 0, 0};
43 int dilation[2] = {1, 1};
44 float bias[] = {1.0f, 2.0f, 3.0f, 4.0f};
45 TestAdderL2Fp32(input_shape, weight_shape, output_shape,
46 stride, padding, dilation, groups, bias);
47}